/***************************************************************************
 *   Copyright (C) 2010 by Oleg Goncharov  *
 *   $EMAIL$                           *                          
 *                                                                         *
 *   This file is part of ChessVision.                                     *
 *                                                                         *
 *   ChessVision is free software; you can redistribute it and/or modify   *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <vector>
#include <opencv/cv.h>
#include <opencv/highgui.h>

#include "cobjectpyrsegmentation.h"

void CObjectPyrSegmentation::SetDefault() {
	min_area = 0.002;
	max_area = 0.1;
	min_area_rect_ratio = 0.0;
	level = 3;
	therehold1 = 100;
	therehold2 = 50;
}

int CObjectPyrSegmentation::DetectObjects(IplImage * img, ObjectList& objs) {
	CvSize s_size = cvGetSize(img);
	CvSize size = cvSize(s_size.width & -(1<<level), s_size.height & -(1<<level));
	IplImage * src = cvCreateImage(size, IPL_DEPTH_8U, 3);
	IplImage * dst = cvCreateImage(size, IPL_DEPTH_8U, 3);
	
	IplImage * mask_3 = cvCreateImage(size, IPL_DEPTH_8U, 3);
	CvMat * mask = cvCreateMat(size.height, size.width, CV_8UC1);
	//выходная маска FloodFill должна быть больше исходного изображения
	CvMat * outmask = cvCreateMat(size.height + 2, size.width + 2, CV_8UC1);
	CvMat * sub_outmask;
	CvRect subrect = cvRect(1, 1, size.width, size.height);
	CvMat submat;
	
	CvMemStorage * storage = cvCreateMemStorage (1000);
	CvSeq *comps;
	CvSeqReader reader;
	CvConnectedComp * comp, new_comp;
	double min = min_area*size.height*size.width;
	double max = max_area*size.height*size.width;
	double min_area;
	double norm_area_left;
	double tmp1, tmp2;
	CvPoint seed;
	int ret;
	
	cvSetImageROI(img, cvRect(0, 0, size.width, size.height));
	cvSmooth(img, src, CV_GAUSSIAN, 7, 7);
	cvResetImageROI(img);
	
	cvPyrSegmentation(src, dst, storage, &comps, level, therehold1, therehold2);
	
	//cvNamedWindow("mask", 1);
	//cvShowImage("mask", dst); cvWaitKey(0);
	
	ret = comps->total;
	cvStartReadSeq( comps, &reader, 0 );
	for(int i = 0; i < comps->total; i++ ) {
		comp = (CvConnectedComp*)reader.ptr;
		
		// находим маску
		cvXorS(dst, comp->value, mask_3);
		cvCvtColor(mask_3, mask, CV_BGR2GRAY);
		cvCmpS(mask, 0, mask, CV_CMP_EQ);
		
		cvDilate(mask, mask);
		cvErode(mask, mask);
		
		//cvShowImage("mask", mask); cvWaitKey(0);
		
		norm_area_left = 1.0;
		do {
			// находим ненулевую точку
			cvMinMaxLoc(mask, &tmp1, &tmp2, 0, &seed);
			if (tmp2 == 0.0) break; // все компоненты найдены
			// заливаем область
			cvSetZero(outmask);
			cvFloodFill(mask, seed, cvRealScalar(255), cvRealScalar(0), cvRealScalar(0), &new_comp, 4 | CV_FLOODFILL_MASK_ONLY, outmask);
			sub_outmask = cvGetSubRect(outmask, &submat, subrect);
			cvSet(mask, cvRealScalar(0), sub_outmask);
			cvCmpS(outmask, 0, outmask, CV_CMP_GT);
			//cvShowImage("mask", mask); cvWaitKey(0);
			//cvShowImage("mask", outmask); cvWaitKey(0);
			// добавляем компоненту
			min_area = min_area_rect_ratio*new_comp.rect.height*new_comp.rect.width;
			if (new_comp.area > min && new_comp.area < max && new_comp.area > min_area ) {
				objs.push_back(new CImageObject(img, sub_outmask, new_comp));
			}
			//оценивем оставшуюся площадь
			norm_area_left -= new_comp.area/comp->area;
		} while (norm_area_left > 0.1);

    	CV_NEXT_SEQ_ELEM(comps->elem_size, reader);
	}
	
	cvReleaseMemStorage(&storage);
	cvReleaseImage(&src);
	cvReleaseImage(&dst);
	cvReleaseImage(&mask_3);
	cvReleaseMat(&mask);
	cvReleaseMat(&outmask);
	return ret;
}

